#/bin/bash

DIR="loops_cycle"
PATHS="paths"

GETENTRYPOINT=0
MAXBBPATH=100
FOLLOWFUNCTIONS=1

#$1 - source file
#$2 - LLVM asm .ll file
#$3 - MODE - loop (printout bbs in cycle, DEFAULT) or tree (printout all bbs in entire tree)
mode=$3

function getbbexits {
# $1 - INPUT filename containing basicblock contents
# $2 - OUTPUT branches filename
# $3 - OUTPUT functioncalls filename
# $4 - currentblockidentifier

# outputs branches and functioncalls to stdout
# outputs branches to file branches
# outputs functioncalls to file functoncalls

   cat $1 | grep "br .*label " | tr "," "\n" | grep -o "label %[a-z0-9\#_]*" | cut -d "%" -f 2 | sort | uniq | sed -e "s/$/,$4/g" > thisbranch
   echo branches: >&2
   cat thisbranch >&2
   cat $1 | grep " nounwind" | grep -o "@[^(]*(" | sort | uniq | sed -e "s/@//g" -e "s/(/#entry/g" | sed -e "s/$/,$4/g" > thisfunction

   echo functions: >&2
   cat thisfunction >&2

   hasreturn=$(grep " ret i32" $1)
   if [ "$hasreturn" != "" ]; then
      # determine return point from state
     # echo STATE: $4
      currfun=$(echo $4 | tr "#" "\n" | grep -m 1 ".")
     # echo CURRFUN: $currfun
      retfun=$(echo $4 | tr "," "\n" | grep -m 1 -v "$currfun")
     # echo HASRETURN: $retfun
      if [ "$retfun" != "" ]; then
         echo $retfun,$4 >> thisbranch
      fi
   fi


   if [ $FOLLOWFUNCTIONS -eq 1 ] ; then
      #echo "Following functions"
      children=$(cat thisbranch thisfunction)
   else
      children=$(cat thisbranch)
   fi

   echo STATE: $4 >&2

    rm -f $2
    for childblock in $children; do
      block=$(echo $childblock | awk -F ',' '{ print $1 }')

          if [ -n "$(echo $4 | grep "$block,\|$block$")"  ]; then
             if [ "$block" == "$headid" ]; then
                echo $srcline:cyclehead:$block,$4
                if [ "$headbranch" == "" ]; then
                   headbranch=$(echo $childblock | grep -o ",[^,]*,$block$" | cut -d "," -f 2)
                   echo headbranch:$headbranch >&2
                fi
                #detect external functions
		echo $4 | tr "," "\n" | sed -e "s/^/\^/g" > pattern
                grep -f pattern assemfile | tr "\!" "\n" | grep " nounwind" | grep -o "@[^(]*(" | sort | uniq | sed -e "s/^@/^\\\(declare\\\|define\\\)\[^@\]\*@/g" > pattern2
		#cat pattern2
                grep -f pattern2 functionsfile2 | sed -e "s/^define[^@]*@/$srcline:INTERNAL:/g" -e "s/^declare[^@]*@/$srcline:EXTERNAL:/g" -e "s/(.*$//g" | tr "\n" "," | sed -e "s/,$/\n/"
             else
                echo $srcline:cycle:$block,$4
             fi
          fi

      echo childbranchblock $block >&2
      if [ "$(grep "$block$" seenblocks)" != "" ]; then
          echo seen $block >&2
          echo $childblock | awk -F ',' '{ print $2 }' | tr "," "\n" >> seenblocks
# was here
      else

        out=$(echo $block | sed -e "s/@\([^(]*\)(/\1/")
        if [ "$mode" == "tree" ]; then
          echo $srcline:$out
        fi
        echo headbranch: $headbranch >&2
        echo childblock: $childblock >&2
        if [ "$headbranch" != "" ] &&  [ "$(echo $childblock | grep "$headbranch")" == "" ]; then
           echo $block >> seenblocks
        fi
           echo $childblock >> $2
      fi

    done
}

srcfile=$(echo $1 | tr "/" "_" | tr " " "_" )

mkdir $DIR 2>/dev/null

# identify lines in src file containing loops
#cat $1 | grep "while[ ]*([^)]*)\|for[ ]*([^)]*)" | grep -v "^[ ]*-:" | cut -d ":" -f 2- | sed -e "s/^ *//g" > $DIR/$srcfile.loops
grep -n "." $1 | grep "while[ ]*([^)]*)\|for[ ]*([^)]*)" > $DIR/$srcfile.loops

if [ true ]; then

cat $2 | sed -e "s/^\(define\|declare\) /\?\1 /g" | tr "\n" "\!" | tr "\?" "\n" > functionsfile
# tag functionnames to bb blocks
rm -f functionsfile2
while read line; do

   if [ -n "$(echo $line | grep "^define \|declare ")" ]; then
      label=$(echo $line | grep -m 1 -o "@[^(^ ]*(" | head -n 1 | sed -e "s/@\([^(]*\)(/\1/g" )
   fi
   echo $line | sed -e "s/\!\([a-z0-9]*:\)/\!$label\#\1/g" -e "s/label %\([a-z0-9]*\)/label %$label\#\1/g" >> functionsfile2
done < functionsfile

cat functionsfile2 | tr "\!" "\n" | sed -e "s/^\([a-z0-9_\#]*:\)/\?\1/g" | tr "\n" "\!" | sed -e "s/\?\([a-z0-9_\#]*:\)/\n\1/g" > assemfile

fi

# for each loop
while read line; do

   # identify the first basic block within that loop
   echo $line
   srcline=$(echo $line | cut -d ":" -f 1)
   #echo $srcline
   grep -m 1 "llvm.dbg.stoppoint(i32 $srcline,.*cmp " assemfile | tr "\!" "\n" > loopbb
   if [ ! -s loopbb ]; then
      srcline=$(echo $srcline + 1 | bc )
      echo trying with srcline=$srcline
      grep -m 1 "llvm.dbg.stoppoint(i32 $srcline,.*cmp " assemfile | tr "\!" "\n" > loopbb
   fi
   if [ ! -s loopbb ]; then
      srcline=$(echo $srcline + 1 | bc )
      echo trying with srcline=$srcline
      grep -m 1 "llvm.dbg.stoppoint(i32 $srcline,.*cmp " assemfile | tr "\!" "\n" > loopbb
   fi
   cat loopbb >&2

   #get headid basicblock identifier
   headid=$(cat loopbb | grep -o "^[^:]*:" | sed -e "s/://" )
   echo headid: $headid >&2
   if [ "$mode" == "tree" ]; then
     echo $headid
   else
     echo $headid > paths
   fi

   #first entry in seenblocks
   echo $headid > seenblocks
   headbranch=""

   if [ $GETENTRYPOINT -gt 0 ]; then
      echo $srcline:$headid
      continue
   fi
    
   # identify branch blocks and calls
   getbbexits loopbb branches functioncalls $headid
   
   #iterate thru each child basic block
   while read line_childb; do
#    echo line_childb: $line_childb

     if [ $(echo $line_childb | tr "," " " | wc -w) -gt $MAXBBPATH ]; then
        echo $srcline:MAXBBPATH:$headid
        break
     fi

    childb=$(echo $line_childb | awk -F ',' '{ print $1 }')
    #state=$(echo $line_childb | cut -d " " -f 2- )
    
    # distinguish between function calls and basic blocks - retrieve from assemfile or functionsfile accordingly
    if [ "$(echo $childb | grep "^@")" == "" ]; then
      # basic block
      grep -m 1 "^$childb:" assemfile | tr "\!" "\n" > childblock
    else
      # functioncall
      grep -m 1 "^[^@]* $childb" functionsfile2 | tr "\!" "\n" > childblock
      echo functioncall: >&2
      cat childblock >&2
         if [ -n "$(head -n 1 childblock | grep "^declare " )" ]; then
             echo EXTERNAL:$line_childb | cut -d "," -f 1,2 | sed -e "s/@\([^(]*\)(/\1/" >&2
             continue
         fi
    fi
     
      cat childblock >&2
      getbbexits childblock childbranches childfunctioncalls $line_childb

      cat childbranches >> branches

      cat childfunctioncalls >> functioncalls
   done < branches
   #iterate thru each child function

done < $DIR/$srcfile.loops
#done < extract

#tag each bacic block with all called child branches
#and functioncalls
#identify cyclic basic block paths - don't need

